/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package aiaudio.processing.network.network;

import aiaudio.database.tables.NeighbourUserToGroupTable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.neuroph.core.learning.TrainingElement;
import org.neuroph.core.learning.TrainingSet;
import org.neuroph.nnet.Kohonen;

/**
 *
 * @author nastya
 */
public class DBAudioNetwork {

    private Kohonen network;
    private int learningCicles;
    private double minSimilarity;

    public DBAudioNetwork(int learningCicles, double minSimilarity) {
        this.learningCicles = learningCicles;
        this.minSimilarity = minSimilarity;
    }

    public void configure(int userCount, int artistCount, double divisor) {
        network = new Kohonen(artistCount, (int) (userCount / divisor));
        network.randomizeWeights();
    }

    public void train(Iterator<double[]> ratings) {
        TrainingSet trainingSet = new TrainingSet();
        while (ratings.hasNext()) {
            double[] userRatings = ratings.next();
            printInSingleLine(userRatings);
            trainingSet.addElement(new TrainingElement(userRatings));
        }

        for (int i = 0; i < learningCicles; i++) {
            network.learnInSameThread(trainingSet);
            System.out.println("learning: " + i + " from " + learningCicles);
        }
    }

    public void saveGroupping(HTable table, double[] userRatings, byte[] userKey) throws IOException {
        network.setInput(userRatings);
        network.calculate();
        double[] output = network.getOutput();

        Put put = new Put(userKey);

        List<Double> outputAsList = toList(output);
        Double max = Collections.max(outputAsList);
        Double min = Collections.min(outputAsList);

        if (max == min) {
            addToAllGroups(output, put);
        } else {
            addToPertinentGroups(output, min, max, put);
        }
        System.out.println("added");
        table.put(put);
    }

    protected void addToPut(Put put, int i, double similarity) {
        NeighbourUserToGroupTable.addGroupForUser(put, i, similarity);
    }

    private void addToAllGroups(double[] output, Put put) {
        for (int i = 0; i < output.length; i++) {
            addToPut(put, i, 1.0);
        }
    }

    private void addToPertinentGroups(double[] outputs, Double min, Double max,
            Put put) {
        for (int i = 0; i < outputs.length; i++) {
            double output = outputs[i];
            double normalized = (output - min) / (max - min);
            System.out.println("normalized = " + normalized);            
            if (normalized <= minSimilarity) {
                addToPut(put, i, 1 - normalized);
            }
        }
    }

    private List<Double> toList(double[] output) {
        List<Double> outputAsList = new ArrayList<Double>();
        for (int i = 0; i < output.length; i++) {
            outputAsList.add(output[i]);
        }
        return outputAsList;
    }

    private void printInSingleLine(double[] userRatings) {
        String s = "";
        for (double u : userRatings) {
            if(!s.isEmpty()){
                s += "; ";
            }
            s += u;
        }
        System.out.println(s);
    }

}
